/**
 *
 */
package com.pp.ent.base.inject;

import android.content.Context;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

import dalvik.system.DexFile;

/**
 * Author:dengqu
 * Date:2016/7/26
 * package工具类
 */

public class PackageUtils {

    public final static List<String> EMPTY_LIST = new ArrayList<String>(0);

    /**
     * 查找指定package下的class
     *
     * @param packageName package名字，允许正则表达式
     * @param gContext
     * @return 符合要求的classes，全路径名
     * @throws IOException
     */
    public static String[] findClassesInPackage(String packageName, Context gContext) {
        return findClassesInPackage(packageName, EMPTY_LIST, EMPTY_LIST, gContext);
    }

    /**
     * 查找指定package下的class
     *
     * @param packageName package名字，允许正则表达式
     * @param included    包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param excluded    不包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param gContext
     * @return 符合要求的classes，全路径名
     * @throws IOException
     */
    public static String[] findClassesInPackage(String packageName, List<String> included, List<String> excluded, Context gContext) {
        String packageOnly = packageName;
        boolean recursive = false;
        // 递归判断
        if (packageName.endsWith(".*")) {
            packageOnly = packageName.substring(0, packageName.lastIndexOf(".*"));
            recursive = true;
        }

        List<String> vResult = new ArrayList<String>();
        try {
            String packageDirName = packageOnly.replace('.', '/');

            String path = gContext.getPackageManager().getApplicationInfo(gContext.getPackageName(), 0).sourceDir;
            DexFile dexFile = new DexFile(path);
            Enumeration<String> dirs = dexFile.entries();
            while (dirs.hasMoreElements()) {
                String entries = dirs.nextElement();
                // 如果是目录结构
                if (entries.contains(packageOnly)) {
                    String[] entriesList = entries.split("\\.");
                    String className = entriesList[entriesList.length - 1];
                    includeOrExcludeClass(packageOnly,entries, className, included, excluded, vResult);
//					findClassesInDirPackage(packageOnly, included, excluded, URLDecoder.decode(entries, "UTF-8"),recursive, vResult, gContext);
                }
            }

//			PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();
//			PackageManager pm = gContext.getPackageManager();
//			Intent intent = new Intent(packageOnly,null);
//			List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,0);
//			ActivityInfo actInfo = resolveInfos.get(0).activityInfo;
//			String apkPath = actInfo.applicationInfo.sourceDir;
//			String libPath = actInfo.applicationInfo.nativeLibraryDir;
//			PathClassLoader classLoader = new PathClassLoader(apkPath,libPath,gContext.getClassLoader());
//
//			Enumeration<URL> dirs = classLoader.getResources(apkPath + "/" + packageDirName);
//			while (dirs.hasMoreElements()) {
//				URL url = dirs.nextElement();

//			}
//			DexFile dex = new DexFile(gContext.getPackageResourcePath());
//			Enumeration<String> dirs = dex.entries();
//			while (dirs.hasMoreElements()) {
//				String entries = dirs.nextElement();
//				// 如果是目录结构
//				if (entries.contains(packageOnly)) {
////					findClassesInDirPackage(packageOnly, included, excluded, URLDecoder.decode(entries, "UTF-8"),
////							recursive, vResult, gContext);
//					Class<?> entryClass = Class.forName(entries,true,classLoader);
//				}
//			}
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }

        String[] result = vResult.toArray(new String[vResult.size()]);
        return result;
    }

    /**
     * 通过遍历目录的方式查找符合要求的包下的class
     *
     * @param packageName 包名，确定名
     * @param included    包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param excluded    不包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param packagePath 包目录路径
     * @param recursive   是否递归
     * @param classes     结果集
     */
    private static void findClassesInDirPackage(String packageName, List<String> included, List<String> excluded,
                                                String packagePath, final boolean recursive, List<String> classes, Context gContext) {

//		File dir = new File(gContext.getPackageResourcePath(),packagePath);
//		if (!dir.exists() || !dir.isDirectory()) {
//			return;
//		}
//		// 过滤目录和以class后缀的文件
//		File[] dirfiles = dir.listFiles(new FileFilter() {
//			public boolean accept(File file) {
//				return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
//			}
//		});

//		for (File file : dirfiles) {
//			if (file.isDirectory()) {
//				// 递归处理
//				findClassesInDirPackage(packageName + "." + file.getName(), included, excluded, file.getAbsolutePath(),
//						recursive, classes,gContext);
//			} else {
//				String className = file.getName().substring(0, file.getName().length() - 6);
//				includeOrExcludeClass(packageName, className, included, excluded, classes);
//			}
//		}
    }

    /**
     * include exclude过滤
     *
     * @param packageName 包名，确定名
     * @param entrys
     * @param className   短类名，不包含package前缀，确定名
     * @param included    包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param excluded    不包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param classes     结果集
     */
    private static void includeOrExcludeClass(String packageName, String entrys,String className, List<String> included,
                                              List<String> excluded, List<String> classes) {
        if (isIncluded(className, included, excluded)) {
            //classes.add(packageName + '.' + className);
            classes.add(entrys);
        } else {
        }
    }

    /**
     * 是否包含
     *
     * @param name     短类名，不包含package前缀，确定名
     * @param included 包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @param excluded 不包含的类名(短类名，不包含package前缀)，允许正则表达式
     * @return include-true,else-false
     */
    private static boolean isIncluded(String name, List<String> included, List<String> excluded) {
        boolean result = false;
        if (included.size() == 0 && excluded.size() == 0) {
            result = true;
        } else {
            boolean isIncluded = find(name, included);
            boolean isExcluded = find(name, excluded);
            if (isIncluded && !isExcluded) {
                result = true;
            } else if (isExcluded) {
                result = false;
            } else {
                result = included.size() == 0;
            }
        }
        return result;

    }

    private static boolean find(String name, List<String> list) {
        for (String regexpStr : list) {
            if (Pattern.matches(regexpStr, name)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) throws Exception {
        List<String> include = new ArrayList<String>();
        include.add(".*");
        String[] classes = findClassesInPackage("com.yy.ent.commons.accessdb.util.*", include, EMPTY_LIST, null);
        for (String clazz : classes) {
            System.out.println(clazz);
        }

        String className = "com.yy.ent.commons.accessdb.util.BlankUtil";
        Class<?> b = Class.forName(className);
    }
}
